package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient iArticleClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Async
    public void autoScanWmNews(Integer id) {
        System.out.println("开始文章审核");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("休眠结束");
        // 根据ID查询文章详情
        WmNews wmNews = wmNewsMapper.selectById(id);
        // 判断文章是否存在
        if (wmNews == null) {
            log.error("你要审核的文章不存在");
            throw new RuntimeException("你要审核的文章不存在");
        }
        // 文章状态必须为1（提交待审核）才需审核
        if (wmNews.getStatus() != (short) 1) {
            log.error("你要审核的文章状态不需要审核");
            throw new RuntimeException("你要审核的文章状态不需要审核");
        }
        // 从文章提取文本、图片的地址
        Map map = handleTextAndImages(wmNews);

        // 开始文本审核，审核失败需要将文章状态修改
        boolean result = handleTextScan((String) map.get("content"), wmNews);
        // 若文本审核成功，开始进行图片审核，否则审核业务结束
        if (!result) {
            log.error("文本审核失败");
            return;
        }
        // 开始审核图片，审核失败需要将文章状态修改
        result = handleImageScan((List<String>) map.get("images"), wmNews);
        // 若图片审核失败，业务结束
        if (!result) {
            log.error("图片审核失败");
            return;
        }
        // 需要将文章往ap_article进行同步（feign远程调用）
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        // 设置文章布局
        articleDto.setLayout(wmNews.getType());
        // 设置作者ID
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        // 设置文章在ap_article的创建时间
        articleDto.setCreatedTime(new Date());
        // 设置文章ID
        if (wmNews.getArticleId() != null){
            articleDto.setId(wmNews.getArticleId());
        }
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            // 作者名称
            articleDto.setAuthorName(wmUser.getName());
        }
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getArticleId());
        if (wmChannel != null) {
            // 文章所属频道名称
            articleDto.setChannelName(wmChannel.getName());
        }
        ResponseResult responseResult = iArticleClient.saveArticle(articleDto);
        if (responseResult.getCode() == 200) {
            // 文章同步成功
            Object data = responseResult.getData();
            // 文章ID回填到wm_news表中的article_id
            wmNews.setArticleId(Long.valueOf(data.toString()));
            // 修改文章状态为9（审核成功）
            updateStatus((short) 9, "发布成功", wmNews);
        }
    }

    /**
     * 对文章图片进行审核
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {

        boolean result = true;
        //如果没有图片，则认为审核通过
        if (images == null || images.size() == 0) {
            return true;
        }

        //图片去重
        images = images.stream().distinct().collect(Collectors.toList());

        //到minio中下载图片，并存到imageList中
        List<byte[]> imageList = new ArrayList<>();

        try {
            for (String imageURL : images) {
                // 到minio下载图片
                byte[] bytes = fileStorageService.downLoadFile(imageURL);
                // 将字节数组转换为BufferdImage对象
                BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(bytes));
                // 获取图片中的文字
                String textInImage = tess4jClient.doOCR(bimg);
                // 对图片中的文字进行审核
                boolean b = handleTextScan(textInImage, wmNews);
                // 如果图片文字审核失败，则不需要继续审核
                if (!b) {
                    return false;
                }
                imageList.add(bytes);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //调用aliyun接口进行图片审核
        try {
            Map map = greenImageScan.imageScan(imageList);

            if ("block".equals(map.get("suggestion"))) {
                updateStatus((short) 2, "图片审核失败", wmNews);
                result = false;
            }

            if ("review".equals(map.get("suggestion"))) {
                updateStatus((short) 3, "图片需要人工审核", wmNews);
                result = false;
            }

        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 对文本内容进行审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean result = true;
        if (StringUtils.isBlank(content)) {
            return true;
        }
        //1、自敏感词审核
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        //1.1创建dfa树
        SensitiveWordUtil.initMap(sensitiveList);
        //1.2 校验
        Map<String, Integer> senresult = SensitiveWordUtil.matchWords(content);

        if(senresult!=null && senresult.size()>0){
            updateStatus((short)2,"文章中包含有自敏感关键词",wmNews);
            return false;
        }
        try {
            Map map = greenTextScan.greeTextScan(content);
            // 审核失败
            if ("block".equals(map.get("suggestion"))) {
                updateStatus((short) 2, "文本内容审核失败", wmNews);
                result = false;
            }
            //需要人工审核
            if ("review".equals(map.get("suggestion"))) {
                updateStatus((short) 3, "文本内容需要人工审核", wmNews);
                result = false;
            }


        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }

        return result;
    }

    //修改文章状态及原因
    private void updateStatus(short status, String response, WmNews wmNews) {
        wmNews.setStatus(status);
        wmNews.setReason(response);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 抽取文章中的文本和图片地址
     *
     * @param wmNews
     * @return
     */
    private Map handleTextAndImages(WmNews wmNews) {
        StringBuilder content = new StringBuilder();
        List<String> images = new ArrayList<String>();
        // 将文章标题放到StringBuilder中
        content.append(wmNews.getTitle());
        // 将图片的地址放到list中
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            Collections.addAll(images, wmNews.getImages().split(","));
        }
        // 从文章的内容中提取文本和图片
        String newsContent = wmNews.getContent();
        List<Map> mapList = JSON.parseArray(newsContent, Map.class);
        for (Map map : mapList) {
            if (map.get("type").equals("text")) {
                content.append((String) map.get("value"));
            }
            if (map.get("type").equals("image")) {
                images.add((String) map.get("value"));
            }
        }
        Map result = new HashMap();
        result.put("content", content.toString());
        result.put("images", images);

        return result;
    }
}
